package apps.sim.action.handler;

import java.io.File;
import java.io.InputStream;

import apps.sim.core.AHandler;
import apps.sim.core.log.Console;
import apps.sim.core.log.Console.Color;

import com.sun.net.httpserver.HttpExchange;

public class CannedFileHandler extends AHandler {
	private CannedHandlerConfiguration configuration = new CannedHandlerConfiguration();

	public byte[] handle(HttpExchange exchange, String context) throws Exception {
		final InputStream requestBody = exchange.getRequestBody();
		final String req = readInput(requestBody);
		final String cannedFile = getCannedFile(context, req);
		final File file = getFile(context, cannedFile);
		return asByteArray(file);
	}

	protected String getCannedFile(String context, final String req) throws Exception {
		final CannedHandlerConfiguration conf = getHandlerConfiguration();
		final String commaSeparatedAttributes = (conf != null && conf.getCommaSeparatedAttributes() != null) ? conf.getCommaSeparatedAttributes() : "default";
		final String[] split = commaSeparatedAttributes.split(",");
		final StringBuilder builder = new StringBuilder();
		for (String string : split) {
			String value = null;
			if (string.equals("default")) {
				value = "default";
			} else if (string.equals("#request")) {
				value = extractRequestName(req);
			} else {
				value = getGetAttributeValue(req, string);
			}
			builder.append(!value.equals("") ? value : "default");
			builder.append("_");
		}
		final int length = builder.length();
		builder.delete(length - 1, length);
		builder.append(".xml");
		return builder.toString();
	}

	private String extractRequestName(String req) {
		if (getHandlerConfiguration().isSoapRequest()) {
			final String bodyTag = ":Body";
			final int indexOf = req.indexOf(bodyTag);
			if (indexOf != -1) {
				final int start = req.indexOf("<", indexOf + bodyTag.length());
				int end = req.indexOf(" ", start + 1);
				if (end == -1) {
					end = req.indexOf(">", start + 1);
				}
				if (start != -1 && end != -1) {
					final String substring = req.substring(start + 1, end);
					return substring.contains(":") ? substring.split(":")[1] : substring;
				}
			} else {
				final String bodyTag2 = "Body";
				final int indexOf2 = req.indexOf(bodyTag);
				if (indexOf2 != -1) {
					final int start = req.indexOf("<", indexOf2 + bodyTag2.length());
					int end = req.indexOf(" ", start + 1);
					if (end == -1) {
						end = req.indexOf(">", start + 1);
					}
					if (start != -1 && end != -1) {
						final String substring = req.substring(start + 1, end);
						return substring.contains(":") ? substring.split(":")[1] : substring;
					}
				}
			}
		} else {
			final int start = req.indexOf("<");
			int end = req.indexOf(" ", start + 1);
			if (end == -1) {
				end = req.indexOf(">", start + 1);
			}
			if (start != -1 && end != -1) {
				final String substring = req.substring(start + 1, end);
				return substring.contains(":") ? substring.split(":")[1] : substring;
			}
		}
		return "default";
	}

	@Override
	public String getContentType() {
		return "text/xml;charset=utf-8";
	}

	public String getGetAttributeValue(String req, String attribute) throws Exception {
		String correlationId = "";
		String matchString = attribute + "=\"";
		int index = req.indexOf(matchString);
		if (index != -1) {
			int in2 = req.indexOf("\"", index + matchString.length());
			correlationId = req.substring(index + matchString.length(), in2);
		}
		if (correlationId.equals("")) {
			throw new Exception("Attribute not found in the request : " + attribute);
		}
		return correlationId;
	}

	public File getFile(final String context, String file) {
		final CannedHandlerConfiguration conf = getHandlerConfiguration();
		String root = (conf != null && conf.getRootDirectory() != null) ? conf.getRootDirectory() : null;
		final File absFile = new File(root + SEPARATOR + context + SEPARATOR + file);
		if (!absFile.exists()) {
			Console.print("Response file not found: " + absFile.getAbsolutePath(), Color.WARNING);
		}
		return absFile;
	}

	public String getDescription() {
		return "This returns response from stored files. Files can be looked up using configured attributes. #request denotes request name.";
	}

	public CannedHandlerConfiguration getHandlerConfiguration() {
		return configuration;
	}

	public void setHandlerConfiguration(IHandlerConfig config) {
		this.configuration = (CannedHandlerConfiguration) config;
	}

	public static class CannedHandlerConfiguration implements IHandlerConfig {

		private String rootDirectory = "/home";
		private String commaSeparatedAttributes = "#request";
		private boolean soapRequest = true;

		public boolean isSoapRequest() {
			return soapRequest;
		}

		@Config(descrition = "If the Request is of SOAP type")
		public void setSoapRequest(boolean soapRequest) {
			this.soapRequest = soapRequest;
		}

		public String getRootDirectory() {
			return rootDirectory;
		}

		@Config(descrition = "Directory of the canned files")
		public void setRootDirectory(String rootDirectory) {
			this.rootDirectory = rootDirectory;
		}

		public String getCommaSeparatedAttributes() {
			return commaSeparatedAttributes;
		}

		@Config(descrition = "Comma separated values of attributes to be used for reading canned file. #request means root element name.")
		public void setCommaSeparatedAttributes(String commaSeparatedAttributes) {
			this.commaSeparatedAttributes = commaSeparatedAttributes;
		}

		@Action(descrition = "What is Comma separated attributes")
		public String description() {
			return "<pre style=\"color:blue\">Shycop will search files under &lt;ROOT_FOLDER&gt;/&lt;CONTEXT&gt; <br/> To search files using attributes, configure comma separated attributes.<br/> #request is used for SOAP request name. <br/>A value of #request,Attr1,Att2 means it will search a file <br/> under root directory with name #request_Att1_att2.xml (not names, by values)<br/></pre>";
		}

		@Override
		public String asString() {
			return rootDirectory + ARG_SEPARATOR + commaSeparatedAttributes + ARG_SEPARATOR + soapRequest;
		}

		@Override
		public void fromString(String string) {
			String[] split = string.split(ARG_SEPARATOR_REGEX);
			this.setRootDirectory(split[0]);
			this.setCommaSeparatedAttributes(split[1]);
			this.soapRequest = Boolean.parseBoolean(split[2]);
		}

		@Override
		public IHandlerConfig cloneInstance() {
			final CannedHandlerConfiguration config = new CannedHandlerConfiguration();
			config.setRootDirectory(this.getRootDirectory());
			config.setCommaSeparatedAttributes(this.getCommaSeparatedAttributes());
			config.setSoapRequest(this.isSoapRequest());

			return config;
		}
	}
}
